﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using XFControls.XFPanels;
using XFControls.XFPanels.XFPanelItems;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Net;
using System.Threading;
using System.Xml.Linq;
using System.Text.RegularExpressions;

namespace XFControls
{
    public interface IUpdateable
    {
        void StartUpdates();
        bool Show { get; set; }
        int GetNumber();
        event EventHandler Updated;
    }

    public struct BlendFunction
    {
        public byte BlendOp;
        public byte BlendFlags;
        public byte SourceConstantAlpha;
        public byte AlphaFormat;
    }

    public struct TRIVERTEX
    {
        private int x;
        private int y;
        private ushort Red;
        private ushort Green;
        private ushort Blue;
        private ushort Alpha;
        public TRIVERTEX(int x, int y, Color color) : this(x, y, color.R, color.G, color.B, color.A) { }
        public TRIVERTEX(int x, int y, ushort red, ushort green, ushort blue, ushort alpha)
        {
            this.x = x;
            this.y = y;
            Red = (ushort)(red << 8);
            Green = (ushort)(green << 8);
            Blue = (ushort)(blue << 8);
            Alpha = (ushort)(alpha << 8);
        }
    }

    public struct GRADIENT_RECT
    {
        private uint UpperLeft;
        private uint LowerRight;
        public GRADIENT_RECT(uint ul, uint lr)
        {
            UpperLeft = ul;
            LowerRight = lr;
        }
    }

    public enum BlendOperation : byte
    {
        AC_SRC_OVER = 0x00
    }

    public enum BlendFlags : byte
    {
        Zero = 0x00
    }

    public enum SourceConstantAlpha : byte
    {
        Transparent = 0x00,
        Opaque = 0xFF
    }

    public enum AlphaFormat : byte
    {
        AC_SRC_ALPHA = 0x01
    }

    public enum CachedImageType
    {
        Icon,
        Picture,
        ProfileHeader
    }

    public enum GradientFillDirection { Horizontal = 0x00000000, Vertical = 0x00000001 }

    public class PlatformAPIs
    {
        [DllImport("coredll.dll")]
        extern public static Int32 AlphaBlend(IntPtr hdcDest,
                                              Int32 xDest,
                                              Int32 yDest,
                                              Int32 cxDest,
                                              Int32 cyDest,
                                              IntPtr hdcSrc,
                                              Int32 xSrc,
                                              Int32 ySrc,
                                              Int32 cxSrc,
                                              Int32 cySrc,
                                              BlendFunction blendFunction);
        [DllImport("coredll.dll")]
        extern public static bool GradientFill(IntPtr hdc,
            TRIVERTEX[] pVertex,
            uint dwNumVertex,
            GRADIENT_RECT[] pMesh,
            uint dwNumMesh,
            uint dwMode);
    }

    public enum PixelFormatID : int
    {
        PixelFormatIndexed = 0x00010000, // Indexes into a palette 
        PixelFormatGDI = 0x00020000, // Is a GDI-supported format 
        PixelFormatAlpha = 0x00040000, // Has an alpha component 
        PixelFormatPAlpha = 0x00080000, // Pre-multiplied alpha 
        PixelFormatExtended = 0x00100000, // Extended color 16 bits/channel 
        PixelFormatCanonical = 0x00200000,

        PixelFormatUndefined = 0,
        PixelFormatDontCare = 0,

        PixelFormat1bppIndexed = (1 | (1 << 8) | PixelFormatIndexed | PixelFormatGDI),
        PixelFormat4bppIndexed = (2 | (4 << 8) | PixelFormatIndexed | PixelFormatGDI),
        PixelFormat8bppIndexed = (3 | (8 << 8) | PixelFormatIndexed | PixelFormatGDI),
        PixelFormat16bppRGB555 = (5 | (16 << 8) | PixelFormatGDI),
        PixelFormat16bppRGB565 = (6 | (16 << 8) | PixelFormatGDI),
        PixelFormat16bppARGB1555 = (7 | (16 << 8) | PixelFormatAlpha | PixelFormatGDI),
        PixelFormat24bppRGB = (8 | (24 << 8) | PixelFormatGDI),
        PixelFormat32bppRGB = (9 | (32 << 8) | PixelFormatGDI),
        PixelFormat32bppARGB = (10 | (32 << 8) | PixelFormatAlpha | PixelFormatGDI | PixelFormatCanonical),
        PixelFormat32bppPARGB = (11 | (32 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatGDI),
        PixelFormat48bppRGB = (12 | (48 << 8) | PixelFormatExtended),
        PixelFormat64bppARGB = (13 | (64 << 8) | PixelFormatAlpha | PixelFormatCanonical | PixelFormatExtended),
        PixelFormat64bppPARGB = (14 | (64 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatExtended),
        PixelFormatMax = 15
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public enum BufferDisposalFlag : int
    {
        BufferDisposalFlagNone,
        BufferDisposalFlagGlobalFree,
        BufferDisposalFlagCoTaskMemFree,
        BufferDisposalFlagUnmapView
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public enum InterpolationHint : int
    {
        InterpolationHintDefault,
        InterpolationHintNearestNeighbor,
        InterpolationHintBilinear,
        InterpolationHintAveraging,
        InterpolationHintBicubic
    }

    [Flags]
    public enum ImageLockMode
    {
        ImageLockModeRead = 0x0001,
        ImageLockModeWrite = 0x0002,
        ImageLockModeUserInputBuf = 0x0004,
    };

#pragma warning disable 0649
    // Pulled from gdiplusimaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public struct BitmapData
    {
        public uint Width;
        public uint Height;
        public int Stride;
        public PixelFormatID PixelFormat;
        public IntPtr Scan0;
        public IntPtr Reserved;
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public struct ImageInfo
    {
        public uint GuidPart1; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public uint GuidPart2; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public uint GuidPart3; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public uint GuidPart4; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public PixelFormatID pixelFormat;
        public uint Width;
        public uint Height;
        public uint TileWidth;
        public uint TileHeight;
        public double Xdpi;
        public double Ydpi;
        public uint Flags;
    }
#pragma warning restore 0649

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    [ComImport, Guid("327ABDA7-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IImagingFactory
    {
        uint CreateImageFromStream(); // This is a place holder, note the lack of arguments 
        uint CreateImageFromFile(string filename, out IImage image);
        // We need the MarshalAs attribute here to keep COM interop from sending the buffer down as a Safe Array. 
        // uint CreateImageFromBuffer([MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image); 
        uint CreateImageFromBuffer(IntPtr buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);
        uint CreateNewBitmap(uint width, uint height, PixelFormatID pixelFormat, out IBitmapImage bitmap);
        uint CreateBitmapFromImage(IImage image, uint width, uint height, PixelFormatID pixelFormat, InterpolationHint hints, out IBitmapImage bitmap);
        uint CreateBitmapFromBuffer(); // This is a place holder, note the lack of arguments 
        uint CreateImageDecoder(); // This is a place holder, note the lack of arguments 
        uint CreateImageEncoderToStream(); // This is a place holder, note the lack of arguments 
        uint CreateImageEncoderToFile(); // This is a place holder, note the lack of arguments 
        uint GetInstalledDecoders(); // This is a place holder, note the lack of arguments 
        uint GetInstalledEncoders(); // This is a place holder, note the lack of arguments 
        uint InstallImageCodec(); // This is a place holder, note the lack of arguments 
        uint UninstallImageCodec(); // This is a place holder, note the lack of arguments 
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    [ComImport, Guid("327ABDA9-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IImage
    {
        uint GetPhysicalDimension(out Size size);
        uint GetImageInfo(out ImageInfo info);
        uint SetImageFlags(uint flags);
        uint Draw(IntPtr hdc, ref Rectangle dstRect, IntPtr srcRect); // "Correct" declaration: uint Draw(IntPtr hdc, ref Rectangle dstRect, ref Rectangle srcRect); 
        uint PushIntoSink(); // This is a place holder, note the lack of arguments 
        uint GetThumbnail(uint thumbWidth, uint thumbHeight, out IImage thumbImage);
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    [ComImport, Guid("327ABDAA-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IBitmapImage
    {
        uint GetSize(out Size size);
        uint GetPixelFormatID(out PixelFormatID pixelFormat);
        uint LockBits(ref Rectangle rect, uint flags, PixelFormatID pixelFormat, out BitmapData lockedBitmapData);
        uint UnlockBits(ref BitmapData lockedBitmapData);
        uint GetPalette(); // This is a place holder, note the lack of arguments 
        uint SetPalette(); // This is a place holder, note the lack of arguments 
    }

    public static class XFControlUtils
    {
        public static void DrawAlpha(Graphics gx, Bitmap image, byte transp, int x, int y)
        {
            using (Graphics gxSrc = Graphics.FromImage(image))
            {
                IntPtr hdcDst = gx.GetHdc();
                IntPtr hdcSrc = gxSrc.GetHdc();
                BlendFunction blendFunction = new BlendFunction();
                blendFunction.BlendOp = (byte)BlendOperation.AC_SRC_OVER;   // Only supported blend operation
                blendFunction.BlendFlags = (byte)BlendFlags.Zero;           // Documentation says put 0 here
                blendFunction.SourceConstantAlpha = transp;// Constant alpha factor
                blendFunction.AlphaFormat = (byte)0;                        // Don't look for per pixel alpha
                PlatformAPIs.AlphaBlend(hdcDst, x, y, image.Width, image.Height, hdcSrc, 0, 0, image.Width, image.Height, blendFunction);
                gx.ReleaseHdc(hdcDst);    // Required cleanup to GetHdc()
                gxSrc.ReleaseHdc(hdcSrc);       // Required cleanup to GetHdc()
            }
        }

        public static void DrawAlpha(Graphics gx, Bitmap image, byte transp, Rectangle recDest, Rectangle recSrc)
        {
            using (Graphics gxSrc = Graphics.FromImage(image))
            {
                IntPtr hdcDst = gx.GetHdc();
                IntPtr hdcSrc = gxSrc.GetHdc();
                BlendFunction blendFunction = new BlendFunction();
                blendFunction.BlendOp = (byte)BlendOperation.AC_SRC_OVER;   // Only supported blend operation
                blendFunction.BlendFlags = (byte)BlendFlags.Zero;           // Documentation says put 0 here
                blendFunction.SourceConstantAlpha = transp;// Constant alpha factor
                blendFunction.AlphaFormat = (byte)0;                        // Don't look for per pixel alpha
                PlatformAPIs.AlphaBlend(hdcDst, recDest.X, recDest.Y, recDest.Width, recDest.Height, hdcSrc, recSrc.X, recSrc.Y, recSrc.Width, recSrc.Height, blendFunction);
                gx.ReleaseHdc(hdcDst);    // Required cleanup to GetHdc()
                gxSrc.ReleaseHdc(hdcSrc);       // Required cleanup to GetHdc()
            }
        }

        public static void DrawAlphaFirstPix(Graphics gx, Bitmap image, int x, int y)
        {
            DrawAlphaFirstPix(gx, image, x, y, image.Width, image.Height);
        }

        public static void DrawAlphaFirstPix(Graphics gx, Bitmap image, int x, int y, int width, int height)
        {
            ImageAttributes attrib = new ImageAttributes();
            Color color = GetTransparentColor(image);
            Rectangle clientArea = new Rectangle(x, y, width, height);

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, clientArea, 0, 0, clientArea.Width, clientArea.Height,
                             GraphicsUnit.Pixel, attrib);
        }

        public static void DrawAlphaFirstPix(Graphics gx, Bitmap image, int x, int y, int width, int height, int offset)
        {
            ImageAttributes attrib = new ImageAttributes();
            Color color = GetTransparentColor(image);
            Rectangle clientArea = new Rectangle(x, y, width, height);

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, clientArea, offset, 0, clientArea.Width, clientArea.Height,
                             GraphicsUnit.Pixel, attrib);
        }

        public static void DrawAlphaFirstPix(Graphics gx, Bitmap image, Rectangle recDest, Rectangle recSrc)
        {
            ImageAttributes attrib = new ImageAttributes();
            Color color = GetTransparentColor(image);

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, recDest, recSrc.X, recSrc.Y, recSrc.Width, recSrc.Height,
                             GraphicsUnit.Pixel, attrib);
        }

        public static void DrawJustifiedString(Graphics g, int x, int y, int width, string Text, Font TextFont, Color c)
        {
            DrawJustifiedString(g, x, y, width, Text, TextFont, c, false);
        }

        public static void DrawJustifiedString(Graphics g, int x, int y, int width, string Text, Font TextFont, Color c, bool format)
        {
            if (format == true)
                Text = GetSizedString(width, Text, TextFont);

            int curX = x, curY = y;

            using (SolidBrush b = new SolidBrush(c))
            {
                foreach (var line in Text.Split('\n'))
                {
                    if (Text.Split('\n').Last() == line)
                        g.DrawString(line, TextFont, b, curX, curY);

                    else
                    {
                        var words = line.Split(' ');
                        SizeF lineMeasure = getLineMeasure(line, g, TextFont);
                        int spaceWidth = (width - (int)lineMeasure.Width) / (words.Length > 1 ? words.Length - 1 : words.Length);

                        foreach (var word in words)
                        {
                            SizeF wordMeasure = g.MeasureString(word, TextFont);
                            g.DrawString(word, TextFont, b, curX, curY);
                            curX += (int)wordMeasure.Width + spaceWidth;
                        }

                        curY += (int)lineMeasure.Height;
                        curX = x;
                    }
                }
            }
        }

        public static void GradientFill(this Graphics graphics, Rectangle rectangle, Color startColor, Color endColor, GradientFillDirection direction)
        {
            var tva = new TRIVERTEX[2];
            tva[0] = new TRIVERTEX(rectangle.Right, rectangle.Bottom, endColor);
            tva[1] = new TRIVERTEX(rectangle.X, rectangle.Y, startColor);
            var gra = new[] { new GRADIENT_RECT(0, 1) };
            var hdc = graphics.GetHdc();
            try
            {
                PlatformAPIs.GradientFill(hdc, tva, (uint)tva.Length, gra, (uint)gra.Length, (uint)direction);
            }
            finally
            {
                graphics.ReleaseHdc(hdc);
            }
        }

        public static int GetSizedStringHeight(int width, string Text, Font TextFont)
        {
            using (Bitmap bm = new Bitmap(100, 100))
            {
                //int width = Screen.PrimaryScreen.WorkingArea.Width;
                int _height;
                var gr = Graphics.FromImage(bm);
                Text = XFControlUtils.GetSizedString(width - 20, Text, TextFont);
                _height = (int)gr.MeasureString(Text, TextFont).Height + 5;
                gr.Dispose();

                return _height;
            }
        }

        public static SizeF GetSizedStringMeasure(int width, string Text, Font TextFont)
        {
            using (Bitmap bm = new Bitmap(100, 100))
            {
                //int width = Screen.PrimaryScreen.WorkingArea.Width;
                var gr = Graphics.FromImage(bm);
                Text = XFControlUtils.GetSizedString(width, Text, TextFont);
                var ret = gr.MeasureString(Text, TextFont);
                gr.Dispose();

                return ret;
            }
        }

        public static SizeF GetEllipsisStringMeasure(int width, string Text, Font TextFont)
        {
            using (Bitmap bm = new Bitmap(100, 100))
            {
                //int width = Screen.PrimaryScreen.WorkingArea.Width;
                var gr = Graphics.FromImage(bm);
                Text = XFControlUtils.EllipsisWord(width, Text, TextFont);
                var ret = gr.MeasureString(Text, TextFont);
                gr.Dispose();

                return ret;
            }
        }

        public static string EllipsisWord(int width, string Text, Font TextFont)
        {
            string buffer = "";
            string full = "";
            Bitmap bm = new Bitmap(100, 100);
            var gr = Graphics.FromImage(bm);

            if (gr.MeasureString(Text, TextFont).Width < width)
                return Text;

            foreach (var s in Text.ToCharArray())
            {
                string temp = "";

                if (string.IsNullOrEmpty(buffer))
                    temp = s + "";
                else
                    temp = buffer + s;
                var tLength = gr.MeasureString(temp + "...", TextFont);

                if (tLength.Width > width)
                {
                    full = buffer + "...";
                    break;
                }
                else
                {
                    buffer = temp;
                }
            }
            bm.Dispose();
            gr.Dispose();

            if (string.IsNullOrEmpty(full))
                full = buffer;

            return full;
        }

        public static string GetSizedString(int width, string Text, Font TextFont)
        {
            if (string.IsNullOrEmpty(Text))
                return "";

            string buffer = "";
            string full = "";
            Bitmap bm = new Bitmap(100, 100);
            var gr = Graphics.FromImage(bm);

            List<string> words = new List<string>(Text.Split(' '));
            foreach (string s in words)
            {
                string temp = "";

                if (string.IsNullOrEmpty(buffer))
                    temp = s;
                else
                    temp = buffer + " " + s;
                var tLength = gr.MeasureString(temp, TextFont);

                if (tLength.Width > width)
                {
                    if (string.IsNullOrEmpty(full))
                        full = buffer;
                    else
                        full += "\n" + buffer;
                    buffer = s;

                    if (gr.MeasureString(buffer, TextFont).Width > width)
                        buffer = splitWord(width, buffer, TextFont);
                }
                else
                {
                    buffer = temp;
                }
            }
            bm.Dispose();
            gr.Dispose();

            if (string.IsNullOrEmpty(full))
                full = buffer;
            else
                full += "\n" + buffer;

            return full;
        }

        public static void DrawBackground(XFItemStyle Style, Graphics g, int x, int y, int width, int height)
        {
            if (Style.BackgroundImage == null)
            {
                if (Style.BackgroundColor == null)
                    return;

                using (SolidBrush b = new SolidBrush(Style.BackgroundColor))
                    g.FillRectangle(b, x, y, width, height);

                return;
            }
            var destRec = new Rectangle(x, y, width, height);
            var srcRec = new Rectangle(0, 0, Style.BackgroundImage.Width, Style.BackgroundImage.Height);

            g.DrawImage(Style.BackgroundImage, destRec, srcRec, GraphicsUnit.Pixel);
        }

        public static void DrawBackgroundSelected(XFItemStyle Style, Graphics g, int x, int y, int width, int height)
        {
            if (Style.SelectedBackgroundImage == null)
            {
                if (Style.SelectedBackgroundColor == null)
                    return;

                using (SolidBrush b = new SolidBrush(Style.SelectedBackgroundColor))
                    g.FillRectangle(b, x, y, width, height);

                return;
            }
            var destRec = new Rectangle(x, y, width, height);
            var srcRec = new Rectangle(0, 0, Style.SelectedBackgroundImage.Width, Style.SelectedBackgroundImage.Height);

            g.DrawImage(Style.SelectedBackgroundImage, destRec, srcRec, GraphicsUnit.Pixel);
        }

        public static void DrawBoarders(XFItemStyle Style, Graphics g, int x, int y, int width, int height)
        {
            if (Style.BoarderBottom)
                using (Pen p = new Pen(Style.BoarderBottomColor) { DashStyle = Style.DashStyleBottom })
                    g.DrawLine(p, x, y + (height - 1), width, y + (height - 1));
            if (Style.BoarderLeft)
                using (Pen p = new Pen(Style.BoarderLeftColor) { DashStyle = Style.DashStyleLeft })
                    g.DrawLine(p, x, y + 1, x, y + (height - 1));
            if (Style.BoarderRight)
                using (Pen p = new Pen(Style.BoarderRightColor) { DashStyle = Style.DashStyleRight })
                    g.DrawLine(p, width, y + 1, width, y + (height - 1));
            if (Style.BoarderTop)
                using (Pen p = new Pen(Style.BoarderTopColor) { DashStyle = Style.DashStyleTop })
                    g.DrawLine(p, x, y + 1, width, y + 1);
        }

        public static void DrawBlackout(Graphics g, Rectangle _blackout)
        {
            using (Bitmap img = new Bitmap(_blackout.Width, _blackout.Height))
            {
                using (var gf = Graphics.FromImage(img))
                using (SolidBrush b = new SolidBrush(Color.Black))
                    gf.FillRectangle(b, 0, 0, _blackout.Width, _blackout.Height);

                DrawAlpha(g, img, 200, _blackout.X, _blackout.Y);
            }
        }

        public static string GetCurrent_Directory()
        {
            return Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
        }

        public static string Decrypt(this string value)
        {
            value = ConvertToASCII(value);
            byte[] binary = Encoding.UTF8.GetBytes(value);
            byte[] key = Encoding.UTF8.GetBytes("This is the key file");
            byte[] encrypted = new byte[binary.Length];
            for (int i = 0, j = 0; i < binary.Length; i++)
            {
                encrypted[i] = Convert.ToByte(binary[i] ^ key[j]);
                if (j < key.Length - 1)
                    j++;
                else
                    j = 0;
            }
            return Encoding.UTF8.GetString(encrypted, 0, encrypted.Length);
        }

        public static string Encrypt(this string password)
        {
            byte[] binary = Encoding.UTF8.GetBytes(password);
            byte[] key = Encoding.UTF8.GetBytes("This is the key file");
            byte[] encrypted = new byte[binary.Length];
            for (int i = 0, j = 0; i < binary.Length; i++)
            {
                encrypted[i] = Convert.ToByte(binary[i] ^ key[j]);
                if (j < key.Length - 1)
                    j++;
                else
                    j = 0;
            }
            string ret = Encoding.UTF8.GetString(encrypted, 0, encrypted.Length);
            ret = ConvertToHex(ret);
            return ret;
        }

        private static string ConvertToHex(string asciiString)
        {
            string hex = "";
            foreach (char c in asciiString)
            {
                int tmp = c;
                hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
            }
            return hex;
        }

        private static string ConvertToASCII(string hexString)
        {
            string str = "";
            string temp = "";
            try
            {
                foreach (char ch in hexString)
                {
                    if (!string.IsNullOrEmpty(temp))
                    {
                        temp += ch.ToString();
                        byte newByte = byte.Parse(temp, System.Globalization.NumberStyles.HexNumber);
                        int i = Convert.ToInt32(newByte.ToString()); // i now = 65
                        str += Convert.ToChar(i);
                        temp = "";
                    }
                    else
                    {
                        temp = ch.ToString();
                    }
                }
            }
            catch { }
            return str;
        }

        private static string splitWord(int width, string Text, Font TextFont)
        {
            string buffer = "";
            string full = "";
            Bitmap bm = new Bitmap(100, 100);
            var gr = Graphics.FromImage(bm);

            foreach (var s in Text.ToCharArray())
            {
                string temp = "";

                if (string.IsNullOrEmpty(buffer))
                    temp = s + "";
                else
                    temp = buffer + s;
                var tLength = gr.MeasureString(temp, TextFont);

                if (tLength.Width > width)
                {
                    if (string.IsNullOrEmpty(full))
                        full = buffer;
                    else
                        full += "\n" + buffer;
                    buffer = s + "";

                    if (gr.MeasureString(buffer, TextFont).Width > width)
                        buffer = splitWord(width, buffer, TextFont);
                }
                else
                {
                    buffer = temp;
                }
            }
            bm.Dispose();
            gr.Dispose();

            if (string.IsNullOrEmpty(full))
                full = buffer;
            else
                full += "\n" + buffer;

            return full;
        }

        private static SizeF getLineMeasure(string line, Graphics g, Font TextFont)
        {
            string temp = line.Replace(" ", "");
            return g.MeasureString(temp, TextFont);
        }

        private static Color GetTransparentColor(Bitmap image)
        {
            return image.GetPixel(0, 0);
        }
    }

    public static class XFGraphics
    {
        private static Dictionary<string, Bitmap> _imageCache;
        private static Dictionary<string, Bitmap> imageCache
        {
            get
            {
                if (_imageCache == null)
                    _imageCache = new Dictionary<string, Bitmap>();

                return _imageCache;
            }
            set
            {
                _imageCache = value;
            }
        }
        private static Queue<ImageRequest> _list;
        private static string localPath;
        private static string xmlPath;
        private static XDocument imageData;
        internal static XDocument ImageData
        {
            get
            {
                if (imageData == null)
                {
                    try
                    {
                        if (string.IsNullOrEmpty(localPath))
                            localPath = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);

                        xmlPath = localPath + @"\XFImageCache.xml";
                        imageData = XDocument.Load(xmlPath);
                    }
                    catch (Exception)
                    {
                        imageData = new XDocument(
                            new XDeclaration("1.0", "utf-8", "yes"),
                            new XElement("imageCacheData"));
                    }
                }
                return imageData;
            }
        }

        public delegate void GetImageDelegate(Image img);

        public static void DoImport()
        {
            foreach (var elm in ImageData.Root.Elements("image").Where(i => i.Attribute("type").Value == "icon"))
            {
                imageCache.Add(elm.Attribute("uri").Value.Decrypt(), new Bitmap(elm.Value));
            }

            var dir = Directory.GetFiles(localPath + @"\Resources\");

            foreach (var file in dir)
            {
                string ext = file.Split('\\').Last();
                imageCache.Add(ext, new Bitmap(file));
            }
        }

        public static void DrawIcon(this IXFItem item, string Uri, Graphics g, Rectangle recDest)
        {
            if (imageCache.ContainsKey(Uri))
            {
                Image i = imageCache[Uri];
                Rectangle recSrc = new Rectangle(0, 0, i.Width, i.Height);
                g.DrawImage(imageCache[Uri], recDest, recSrc, GraphicsUnit.Pixel);
            }
            else
            {
                DrawUI(item, "iconThumb", g, recDest);
                addToList(item, Uri, (i) =>
                {
                    cacheIcon(Uri, i);
                    Rectangle recSrc = new Rectangle(0, 0, i.Width, i.Height);
                    if (item.Buffer != null)
                        using (Graphics gi = Graphics.FromImage(item.Buffer))
                            gi.DrawImage(i, recDest, recSrc, GraphicsUnit.Pixel);
                });
            }
        }

        public static void DrawImage(this IXFItem item, string Uri, Graphics g, Rectangle recDest, bool maintainAspectRatio)
        {
            if (imageCache.ContainsKey(Uri))
            {
                Image i = imageCache[Uri];
                Rectangle recSrc = new Rectangle(0, 0, i.Width, i.Height);
                if (!maintainAspectRatio)
                    g.DrawImage(i, recDest, recSrc, GraphicsUnit.Pixel);
                else
                {
                    // TODO:  Add aspect ratio stuff here
                    g.DrawImage(i, recDest, recSrc, GraphicsUnit.Pixel);
                }
            }
            else
            {
                DrawUI(item, "image", g, recDest);
                addToList(item, Uri, (i) =>
                {
                    cacheImage(Uri, i);
                    Rectangle recSrc = new Rectangle(0, 0, i.Width, i.Height);
                    if (item.Buffer != null)
                        using (Graphics gi = Graphics.FromImage(item.Buffer))
                            gi.DrawImage(i, recDest, recSrc, GraphicsUnit.Pixel);
                });
            }
        }

        public static void DrawUI(this IXFItem item, string Uri, Graphics g, Rectangle recDest)
        {
            drawUI(item, Uri, g, recDest);
        }

        public static void DrawUI(this XFPanelBase panel, string Uri, Graphics g, Rectangle recDest)
        {
            drawUI(panel, Uri, g, recDest);
        }

        public static void DrawUI(this IXFButton button, string Uri, Graphics g, Rectangle recDest)
        {
            drawUI(button, Uri, g, recDest);
        }

        private static void drawUI(object sender, string Uri, Graphics g, Rectangle recDest)
        {
            Image i = null;
            if ((i = getUI(Uri)) == null)
                i = getImageAssembly(sender, Uri);

            if (i != null)
            {
                Rectangle recSrc = new Rectangle(0, 0, i.Width, i.Height);
                drawUI(g, i, recDest, recSrc, Uri);
            }
        }

        private static Image getUI(string Uri)
        {
            if (imageCache.Keys.Any(k => k.StartsWith(Uri)))
                return imageCache[imageCache.Keys.First(k => k.StartsWith(Uri))];

            return null;
        }

        private static void drawUI(Graphics g, Image i, Rectangle recDest, Rectangle recSrc, string Uri)
        {
            string type = Uri;
            if (imageCache.Keys.Any(k => k.StartsWith(Uri)))
                type = imageCache.Keys.First(k => k.StartsWith(Uri));

            Regex reg = new Regex(@"_trans_(?<amount>\d+)");
            if (type.Contains("_alpha"))
            {
                if (reg.IsMatch(type))
                {
                }
                //else
                XFControlUtils.DrawAlphaFirstPix(g, new Bitmap(i), recDest, recSrc);
            }
            else if (reg.IsMatch(type))
            {
                byte b = byte.Parse(reg.Match(type).Groups["amount"].Value);
                XFControlUtils.DrawAlpha(g, new Bitmap(i), b, recDest, recSrc);
            }
            else
                g.DrawImage(i, recDest, recSrc, GraphicsUnit.Pixel);
        }

        private static void addToList(IXFItem item, string Uri, GetImageDelegate callback)
        {
            if (_list == null)
            {
                _list = new Queue<ImageRequest>();
                startImageDownloading();
            }
            _list.Enqueue(new ImageRequest(item, Uri, callback));
        }

        private static void startImageDownloading()
        {
            WaitCallback cb = new WaitCallback((v) =>
            {
                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
                while (true)
                {
                    if (_list.Count > 0)
                    {
                        var req = _list.Dequeue();
                        if (req.Item.Parent.IsDisposed)
                            continue;

                        var i = getImageWeb(req.Item, req.Uri);
                        if (i != null)
                            req.Callback(i);
                    }
                    else
                        Thread.Sleep(1000);
                }
            });

            ThreadPool.QueueUserWorkItem(cb);
        }

        private static Image getImageWeb(IXFItem item, string uri)
        {
            try
            {
                return downloadImageFile(uri);
            }
            catch { }

            return null;
        }

        private static Image getImageLocal(string Uri)
        {
            lock (typeof(XFGraphics))
                if (imageCache.ContainsKey(Uri))
                    return imageCache[Uri];

            Bitmap ret = null;
            if (string.IsNullOrEmpty(localPath))
                localPath = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);

            string path = localPath;

            if (File.Exists(path + @"\Resources\" + Uri))
            {
                ret = new Bitmap(path + @"\Resources\" + Uri);
                lock (typeof(XFGraphics))
                    imageCache.Add(Uri, ret);
            }
            return ret;
        }

        private static Image getImageAssembly(object item, string Uri)
        {
            Type t = item.GetType();
            Assembly myAssembly = t.Assembly;
            string ns = myAssembly.GetName().Name;

            try
            {
                Stream myStream = myAssembly.GetManifestResourceStream(ns + ".Resources." + Uri + ".png");
                return new Bitmap(myStream);
            }
            catch (FileNotFoundException) { }
            catch (Exception e)
            {
            }

            return null;
        }

        private static Image downloadImageFile(string url)
        {
            FileStream fsFileStream = null;
            HttpWebRequest webRequest = null;
            HttpWebResponse webResponse = null;
            Stream responseStream = null;
            Bitmap ret = null;

            try
            {
                byte[] BUFFER = new byte[307200]; // 300 KB
                webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Method = "GET";
                webRequest.Timeout = 60000;
                webResponse = (HttpWebResponse)webRequest.GetResponse(); //Getting the response

                if (webResponse.StatusCode.ToString().Equals("OK"))
                {
                    responseStream = webResponse.GetResponseStream();
                    if (responseStream == null)
                        return null;
                    ret = new Bitmap(responseStream);

                    imageCache.Add(url, ret);
                }
            }
            catch (Exception exp) { }
            finally
            {
                if (fsFileStream != null)
                {
                    fsFileStream.Close();
                    fsFileStream = null;
                }
                if (webRequest != null)
                {
                    webRequest = null;
                }
                if (webResponse != null)
                {
                    webResponse.Close();
                    webResponse = null;
                }
            }

            return ret;
        }

        private static bool isCached(string uri)
        {
            return ImageData.Root.Elements().Any(e => e.Name == "image" && e.Attribute("uri").Value == uri.Encrypt());
        }

        private static void cacheImage(string uri, Image i)
        {
            if (i == null)
                return;

            string path = localPath + @"\images\";
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            if (!isCached(uri))
            {
                Guid g = Guid.NewGuid();
                path += g.ToString() + ".png";
                imageData.Root.Add(new XElement("image", new XAttribute("uri", uri.Encrypt()), new XAttribute("guid", g.ToString()), new XAttribute("type", "image"), path));
            }
            else
            {
                var elm = imageData.Root.Elements().First(e => e.Name == "image" && e.Attribute("uri").Value == uri.Encrypt());
                path += elm.Attribute("guid").Value + ".png";
            }

            while (isLocked(path))
                Thread.Sleep(100);

            var stream = File.Create(path);
            i.Save(stream, ImageFormat.Png);

            imageData.Save(xmlPath);
        }

        private static void cacheIcon(string uri, Image i)
        {
            if (i == null)
                return;

            string path = localPath + @"\icons\";
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            if (!isCached(uri))
            {
                Guid g = Guid.NewGuid();
                path += g.ToString() + ".png";
                imageData.Root.Add(new XElement("image", new XAttribute("uri", uri.Encrypt()), new XAttribute("guid", g.ToString()), new XAttribute("type", "icon"), path));
            }
            else
            {
                var elm = imageData.Root.Elements().First(e => e.Name == "image" && e.Attribute("uri").Value == uri.Encrypt());
                path += elm.Attribute("guid").Value + ".png";
            }

            while (isLocked(path))
                Thread.Sleep(100);

            var stream = File.Create(path);
            i.Save(stream, ImageFormat.Png);

            imageData.Save(xmlPath);
        }

        private static bool isLocked(string path)
        {
            if (!File.Exists(path))
                return false;

            FileStream stream = null;

            try
            {
                stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
            }
            catch (IOException)
            {
                return true;
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }

            return false;
        }
    }

    class ImageRequest
    {
        public IXFItem Item { get; set; }
        public string Uri { get; set; }
        public XFControls.XFGraphics.GetImageDelegate Callback { get; set; }

        public ImageRequest(IXFItem item, string uri, XFControls.XFGraphics.GetImageDelegate callback)
        {
            Item = item;
            Uri = uri;
            Callback = callback;
        }
    }
}
